package com.meis.widget.xiaohongshu.tag;


import com.meis.widget.ResourceTable;
import com.meis.widget.utils.PixelUtil;

import cs.help.tool.Log;

import ohos.agp.animation.Animator;
import ohos.agp.animation.AnimatorValue;
import ohos.agp.components.*;
import ohos.app.Context;
import ohos.eventhandler.EventHandler;
import ohos.eventhandler.EventRunner;
import ohos.multimodalinput.event.TouchEvent;

import java.math.BigDecimal;

/**
 * Created by wenshi on 2019/3/12.
 * Description
 */
public class RandomDragTagView extends DirectionalLayout implements
        Component.TouchEventListener, Component.BindStateChangedListener {
    // 左侧视图
    private DirectionalLayout mLeftLayout;
    private Text mLeftText;
    private Component mLeftLine;
    // 右侧视图
    private DirectionalLayout mRightLayout;
    private Text mRightText;
    private Component mRightLine;
    // 中间视图
    private Component mBreathingView;
    private StackLayout mBreathingLayout;
    // 是否显示左侧视图  默认显示左侧视图
    private boolean mIsShowLeftView = true;
    // 呼吸灯动画
    private AnimatorValue mBreathingAnimator;
    // 回弹动画
    private AnimatorValue mReboundAnimator;
    private float mStartReboundX;
    private float mStartReboundY;
    private float mLastMotionRawY;
    private float mLastMotionRawX;
    // 是否多跟手指按下
    private boolean mPointerDown = false;
    // 是否可以拖拽
    private boolean mCanDrag = true;
    // 是否可以拖拽出父控件区域
    private boolean mDragOutParent = true;
    // 父控件最大的高度
    private int mMaxParentHeight = 0;
    // 最大挤压宽度 默认400
    private int mMaxExtrusionWidth = 400;
    // 文本圆角矩形的最大宽度
    private int mMaxTextLayoutWidth = 0;
    // 删除标签区域的高度
    private int mDeleteRegionHeight;
    // 暴露接口
    private boolean mStartDrag = false;
    private OnRandomDragListener mDragListener;
    //开启呼吸灯动画 注动画无线循环注意回收防止内存泄露
    private boolean expand = false;
    private float defAreaY;
    private float defAreaX;

    public RandomDragTagView(Context context) {
        this(context, null);
    }

    public RandomDragTagView(Context context, AttrSet attrs) {
        this(context, attrs, "");
    }

    public RandomDragTagView(Context context, AttrSet attrs, String defStyleAttr) {
        super(context, attrs, defStyleAttr);
        setOrientation(HORIZONTAL);
        LayoutScatter.getInstance(context).parse(ResourceTable.Layout_random_tag_layout, this, true);
        initView();
        setTouchEvent();
        setBindStateChangedListener(this);
        initListener();
        initData();
        startBreathingAnimator();
    }

    private void setTouchEvent() {
        setTouchEventListener(this::onTouchEvent);
    }

    private void startBreathingAnimator() {
        clearBreathingAnimator();
        mBreathingAnimator = new AnimatorValue();
        mBreathingAnimator.setCurveType(Animator.CurveType.LINEAR);
        mBreathingAnimator.setDuration(800);
        mBreathingAnimator.setDelay(200);
        mBreathingAnimator.setLoopedCount(Animator.INFINITE);
        mBreathingAnimator.setValueUpdateListener(new AnimatorValue.ValueUpdateListener() {
            @Override
            public void onUpdate(AnimatorValue animatorValue, float value) {
                float scale = 0F;
                BigDecimal multiply = BigDecimal.valueOf(0.2F).multiply(BigDecimal.valueOf(value));
                if (expand) {
                    scale = BigDecimal.valueOf(1.0F).subtract(multiply).floatValue();
                } else {
                    scale = BigDecimal.valueOf(0.8F).add(multiply).floatValue();
                }
                mBreathingView.setScaleX(scale);
                mBreathingView.setScaleY(scale);
            }
        });
        mBreathingAnimator.setLoopedListener(new Animator.LoopedListener() {
            @Override
            public void onRepeat(Animator animator) {
                expand = !expand;
            }
        });
        mBreathingAnimator.start();
    }

    private void initData() {
        // 默认显示左侧视图 隐藏右侧视图
        visibilityRightLayout();
        getMaxTextLayoutWidth();
        // 删除区域的高度
        mDeleteRegionHeight = BigDecimal.valueOf(PixelUtil.vp2px(60)).intValue();
    }

    /**
     * 获取文本最大宽度
     */
    public void getMaxTextLayoutWidth() {
        mLeftLayout.estimateSize(LayoutConfig.MATCH_CONTENT, LayoutConfig.MATCH_CONTENT);
        mRightLayout.estimateSize(LayoutConfig.MATCH_CONTENT, LayoutConfig.MATCH_CONTENT);
        getContext().getUITaskDispatcher().delayDispatch(new Runnable() {
            @Override
            public void run() {
                mMaxTextLayoutWidth = isShowLeftView() ? mLeftLayout.getEstimatedWidth() : mRightLayout.getEstimatedWidth();
            }
        }, 1);

    }

    private void visibilityLeftLayout() {
        mLeftLayout.setVisibility(mIsShowLeftView ? VISIBLE : HIDE);
        mLeftText.setVisibility(mIsShowLeftView ? VISIBLE : HIDE);
        mLeftLine.setVisibility(mIsShowLeftView ? VISIBLE : HIDE);
    }

    private void visibilityRightLayout() {
        mRightLayout.setVisibility(!mIsShowLeftView ? VISIBLE : HIDE);
        mRightText.setVisibility(!mIsShowLeftView ? VISIBLE : HIDE);
        mRightLine.setVisibility(!mIsShowLeftView ? VISIBLE : HIDE);
    }

    private void initListener() {
        if (!canDragView()) return;
        mBreathingLayout.setClickedListener(new ClickedListener() {
            @Override
            public void onClick(Component component) {
                switchDirection();
            }
        });
    }

    private void initView() {
        mLeftLayout = (DirectionalLayout) findComponentById(ResourceTable.Id_left_tag_layout);
        mLeftText = (Text) findComponentById(ResourceTable.Id_left_tv_tag);
        mLeftLine = findComponentById(ResourceTable.Id_left_line_view);
        mBreathingView = findComponentById(ResourceTable.Id_white_breathing_view);
        mBreathingLayout = (StackLayout) findComponentById(ResourceTable.Id_fl_breathing);
        mRightLayout = (DirectionalLayout) findComponentById(ResourceTable.Id_right_tag_layout);
        mRightText = (Text) findComponentById(ResourceTable.Id_right_tv_tag);
        mRightLine = findComponentById(ResourceTable.Id_right_line_view);

    }

    /**
     * 切换方向
     */
    public void switchDirection() {
        mIsShowLeftView = !mIsShowLeftView;
        visibilityLeftLayout();
        visibilityRightLayout();
        // 第一步更改 重置 textLayout 的高度
        final int preSwitchWidth = getWidth();
        DirectionalLayout.LayoutConfig lp = (LayoutConfig) (isShowLeftView() ?
                mLeftLayout.getLayoutConfig() : mRightLayout.getLayoutConfig());
        lp.width = LayoutConfig.MATCH_CONTENT;
        if (mIsShowLeftView) {
            mLeftText.setText(mRightText.getText());
            mLeftLayout.setLayoutConfig(lp);
        } else {
            mRightText.setText(mLeftText.getText());
            mRightLayout.setLayoutConfig(lp);
        }
        // 第二步 重新设置setTranslationX的值
        getContext().getUITaskDispatcher().asyncDispatch(new Runnable() {
            @Override
            public void run() {
                float newTranslationX = 0;
                if (!isShowLeftView()) {
                    newTranslationX = getTranslationX() + preSwitchWidth - mBreathingView.getWidth();
                } else {
                    newTranslationX = getTranslationX() - getWidth() + mBreathingView.getWidth();
                }
                // 边界检测
                checkBound(newTranslationX, getTranslationY());
            }
        });
    }

    /**
     * 检查边界
     *
     * @param newTranslationX
     * @param newTranslationY
     */
    private void checkBound(float newTranslationX, float newTranslationY) {
        setTranslationX(newTranslationX);
        // 越界的情况下 改变textLayout 的高度
        final int parentWidth = ((Component) getComponentParent()).getWidth();
        int parentHeight = 0;
        if (defAreaY == 0) {
            parentHeight = ((Component) getComponentParent()).getHeight();
        } else {
            parentHeight = BigDecimal.valueOf(defAreaY).intValue();
        }
        float translationX = getTranslationX();
        if (translationX <= 0) {
            extrusionTextRegion(translationX);
        } else if (getTranslationX() >= (parentWidth - getWidth())) {
            final float offsetX = getWidth() - (parentWidth - getTranslationX());
            extrusionTextRegion(-offsetX);
            // 越界检测
            getContext().getUITaskDispatcher().asyncDispatch(new Runnable() {
                @Override
                public void run() {
                    int width = getWidth();
                    if (getTranslationX() >= (parentWidth - width)) {
                        setTranslationX(parentWidth - width);
                    }
                }
            });
        } else {
            Log.i("RandomDragTagView", "checkBound------else ------------------");
        }
        // 越界检测
        if (getTranslationX() <= 0) {
            setTranslationX(0);
        }
        if (newTranslationY <= 0) {
            newTranslationY = 0;
        } else if (newTranslationY >= parentHeight - getHeight()) {
            newTranslationY = parentHeight - getHeight();
        }
        setTranslationY(newTranslationY);
    }


    /**
     * 初始化标签
     *
     * @param text           标签文本
     * @param translationX   相对于父控件的x坐标
     * @param areaX          父控件宽度
     * @param translationY   相对于父控件的y坐标
     * @param areaY          父控件高度
     * @param isShowLeftView 是否显示左侧标签
     */
    public void initTagView(String text, final float translationX, final float areaX, final float translationY
            , final float areaY, boolean isShowLeftView) {
        this.defAreaX = areaX;
        this.defAreaY = areaY;
        initTagView(text, translationX, translationY, isShowLeftView);
        Log.d(getClass().getName(), String.valueOf(defAreaX));
    }

    /**
     * 初始化tagview
     *
     * @param text           显示的文本内容
     * @param translationX   相对于父控件的x坐标
     * @param translationY   相对于父控件的y坐标
     * @param isShowLeftView 是否显示左侧标签
     */
    public void initTagView(String text, final float translationX, final float translationY, boolean isShowLeftView) {
        this.mIsShowLeftView = isShowLeftView;
        visibilityLeftLayout();
        visibilityRightLayout();
        // 不可见
        setVisibility(INVISIBLE);
        // 设置文本控件
        if (mIsShowLeftView) {
            mLeftText.setText(text);
        } else {
            mRightText.setText(text);
        }
        // 获取文本最大宽度
        getMaxTextLayoutWidth();
        getContext().getUITaskDispatcher().delayDispatch(new Runnable() {
            @Override
            public void run() {
                // 边界检测
                checkBound(translationX, translationY);
                // 设置可见
                setVisibility(VISIBLE);
            }
        }, 10);
    }

    @Override
    public boolean onTouchEvent(Component component, TouchEvent touchEvent) {
        if (!canDragView()) {
            return true;
        }
        switch (touchEvent.getAction()) {
            case TouchEvent.PRIMARY_POINT_DOWN:
                Log.i("RandomDragTagView", "TouchEvent.PRIMARY_POINT_DOWN--------");
                final float x = touchEvent.getPointerScreenPosition(touchEvent.getIndex()).getX();
                final float y = touchEvent.getPointerScreenPosition(touchEvent.getIndex()).getY();
                mStartDrag = false;
                mPointerDown = false;
                mLastMotionRawX = x;
                mLastMotionRawY = y;
                mStartReboundX = getTranslationX();
                mStartReboundY = getTranslationY();
                break;
            case TouchEvent.POINT_MOVE:
                Log.i("RandomDragTagView", "TouchEvent.POINT_MOVE--------");
                final float rawY = touchEvent.getPointerScreenPosition(touchEvent.getIndex()).getY();
                final float rawX = touchEvent.getPointerScreenPosition(touchEvent.getIndex()).getX();
                if (!mStartDrag) {
                    mStartDrag = true;
                    if (mDragListener != null) {
                        mDragListener.onStartDrag();
                    }
                }
                if (!mPointerDown) {
                    Log.i("RandomDragTagView", "TouchEvent.POINT_MOVE--------");
                    final float yDiff = rawY - mLastMotionRawY;
                    final float xDiff = rawX - mLastMotionRawX;
                    // 处理move事件
                    handlerMoveEvent(yDiff, xDiff);
                    mLastMotionRawY = rawY;
                    mLastMotionRawX = rawX;
                }
                break;
            case TouchEvent.PRIMARY_POINT_UP:
                Log.i("RandomDragTagView", "TouchEvent.PRIMARY_POINT_UP--------");
                mPointerDown = false;
                mStartDrag = false;

                final float translationY = getTranslationY();
                int parentHeight = 0;
                if (defAreaY == 0) {
                    parentHeight = ((Component) getComponentParent()).getHeight();
                } else {
                    parentHeight = BigDecimal.valueOf(defAreaY).intValue();
                }
                if (mMaxParentHeight == 0) {
                    int parentParentHeight = ((Component) getComponentParent().getComponentParent()).getHeight();
                    mMaxParentHeight = (mDragOutParent ? parentParentHeight : parentHeight) - getHeight();
                }
                if (mMaxParentHeight - mDeleteRegionHeight < translationY) {
                    removeTagView();
                } else if (parentHeight - getHeight() < translationY) {
                    startReBoundAnimator();
                }
                if (mDragListener != null) {
                    mDragListener.onStopDrag();
                }
                break;
        }
        return true;

    }

    // 开始回弹动画
    private void startReBoundAnimator() {
        if (mReboundAnimator != null && mReboundAnimator.isRunning()) {
            mReboundAnimator.cancel();
        }
        mReboundAnimator = new AnimatorValue();
        mReboundAnimator.setDuration(400);
        final float startTransX = getTranslationX();
        final float startTransY = getTranslationY();
        mReboundAnimator.setValueUpdateListener(new AnimatorValue.ValueUpdateListener() {
            @Override
            public void onUpdate(AnimatorValue animatorValue, float v) {
                float value = BigDecimal.valueOf(1).subtract(BigDecimal.valueOf(v)).floatValue();
                setTranslationX(mStartReboundX + (startTransX - mStartReboundX) * value);
                setTranslationY(mStartReboundY + (startTransY - mStartReboundY) * value);
            }
        });
        mReboundAnimator.start();
    }

    /**
     * 处理手势的move事件
     *
     * @param yDiff y轴方向的偏移量
     * @param xDiff x轴方向的偏移量
     */
    private void handlerMoveEvent(float yDiff, float xDiff) {
        float translationX = getTranslationX() + xDiff;
        float translationY = getTranslationY() + yDiff;
        // 越界处理 最大最小原则
        int parentWidth = ((Component) getComponentParent()).getWidth();
        int parentHeight = 0;
        if (defAreaY == 0) {
            parentHeight = ((Component) getComponentParent()).getHeight();
        } else {
            parentHeight = BigDecimal.valueOf(defAreaY).intValue();
        }
        if (mMaxParentHeight == 0) {
            int parentParentHeight = ((Component) getComponentParent().getComponentParent()).getHeight();
            mMaxParentHeight = (mDragOutParent ? parentParentHeight : parentHeight) - getHeight();
        }
        int maxWidth = parentWidth - getWidth();
        // 分情况处理越界 宽度
        if (translationX <= 0) {
            translationX = 0;
            // 标签文本出现挤压效果
            if (isShowLeftView()) {
                extrusionTextRegion(xDiff);
            }
        } else if (translationX >= maxWidth) {
            translationX = maxWidth;
            // 右侧挤压
            if (!isShowLeftView()) {
                extrusionTextRegion(-xDiff);
                handleWidthError();
            }
        } else {
            int textWidth = isShowLeftView() ? mLeftLayout.getWidth() : mRightLayout.getWidth();
            // 左侧视图
            if (isShowLeftView()) {
                if (getTranslationX() == 0 && textWidth < mMaxTextLayoutWidth) {
                    translationX = 0;
                    extrusionTextRegion(xDiff);
                }
            } else {
                if (textWidth < mMaxTextLayoutWidth) {
                    extrusionTextRegion(-xDiff);
                    handleWidthError();
                }
            }
        }
        // 高度越界处理
        if (translationY <= 0) {
            translationY = 0;
        } else if (translationY >= mMaxParentHeight) {
            translationY = mMaxParentHeight;
        }
        setTranslation(translationX, translationY);
    }

    // 处理宽度误差
    private void handleWidthError() {
        new EventHandler(EventRunner.getMainEventRunner()).postTask(new Runnable() {
            @Override
            public void run() {
                if (getComponentParent() == null) return;
                int parentWidth = ((Component) getComponentParent()).getWidth();
                int maxWidth = parentWidth - getWidth();
                setTranslationX(maxWidth);
            }
        });
    }

    /**
     * 挤压拉伸文本区域
     *
     * @param deltaX 偏移量
     */
    private void extrusionTextRegion(float deltaX) {
        int textWidth = isShowLeftView() ? mLeftLayout.getWidth() : mRightLayout.getWidth();

        DirectionalLayout.LayoutConfig lp = (LayoutConfig) (isShowLeftView() ?
                mLeftLayout.getLayoutConfig() : mRightLayout.getLayoutConfig());
        if (textWidth >= mMaxExtrusionWidth) {
            lp.width = (int) (textWidth + deltaX);
            // 越界判定
            if (lp.width <= mMaxExtrusionWidth) {
                lp.width = mMaxExtrusionWidth;
            } else if (lp.width >= mMaxTextLayoutWidth) {
                lp.width = mMaxTextLayoutWidth;
            }
            Log.i("RandomDragTagView", "lp.width = " + lp.width);
            if (isShowLeftView()) {
                mLeftLayout.setLayoutConfig(lp);
            } else {
                mRightLayout.setLayoutConfig(lp);
            }
        }
    }


    /**
     * 调整索引 位于其他标签之上
     * moveToTop(View target) 方法的性能更好
     */
    @Deprecated
    private void adjustIndex() {
        ComponentParent parent = getComponentParent();
        if (parent != null) {
            if (parent instanceof ComponentContainer) {
                ComponentContainer parentView = (ComponentContainer) parent;
                int childCount = parentView.getChildCount();
                if (childCount > 1 && getChildIndex(this) != (childCount - 1)) {
                    parentView.removeComponent(this);
                    parentView.addComponent(this);
                    // 重新开启呼吸灯动画
                    startBreathingAnimator();
                }
            }
        }
    }

    private void moveToTop(Component target) {
        //先确定现在在哪个位置
        int startIndex = getChildIndex(target);
        //计算一共需要几次交换，就可到达最上面
        int count = getChildCount() - 1 - startIndex;
        for (int i = 0; i < count; i++) {
            //更新索引
            int fromIndex = getChildIndex(target);
            //目标是它的上层
            int toIndex = fromIndex + 1;
            //获取需要交换位置的两个子View
            Component from = target;
            Component to = getComponentAt(toIndex);

            //先把它们拿出来
            removeComponentAt(toIndex);
            removeComponentAt(fromIndex);
            //再放回去，但是放回去的位置(索引)互换了
            addComponent(to, fromIndex, to.getLayoutConfig());
            addComponent(from, toIndex, from.getLayoutConfig());
        }
        //刷新
        invalidate();
    }

    // 移除标签view
    private void removeTagView() {
        ComponentParent parent = getComponentParent();
        if (parent != null) {
            if (parent instanceof ComponentContainer) {
                ComponentContainer parentView = (ComponentContainer) parent;
                parentView.removeComponent(this);
            }
        }
    }

    //

    /**
     * 是否可以拖拽
     *
     * @return boolean mCanDrag
     */
    public boolean canDragView() {
        return mCanDrag;
    }

    /**
     * 是否显示左边View
     *
     * @return boolean  mIsShowLeftView
     */
    public boolean isShowLeftView() {
        return mIsShowLeftView;
    }

    /**
     * 获取tag文本
     *
     * @return String 文本
     */
    public String getTagText() {
        if (isShowLeftView()) {
            return mLeftText.getText().toString();
        }
        return mRightText.getText().toString();
    }

    /**
     * 获取父控件X轴偏移量
     *
     * @return float PercentTransX
     */
    public float getPercentTransX() {
        int parentWidth = ((Component) getComponentParent()).getWidth();
        return getTranslationX() / parentWidth;
    }

    public float getPercentTransY() {
        int parentHeight = getPercentHeight();
        return getTranslationY() / parentHeight;
    }

    private int getPercentHeight() {
        int parentHeight = 0;
        if (defAreaY == 0) {
            parentHeight = ((Component) getComponentParent()).getHeight();
        } else {
            parentHeight = BigDecimal.valueOf(defAreaY).intValue();
        }
        return parentHeight;
    }

    public void setShowLeftView(boolean showLeftView) {
        mIsShowLeftView = showLeftView;
    }

    public void setMaxExtrusionWidth(int maxExtrusionWidth) {
        mMaxExtrusionWidth = maxExtrusionWidth;
    }

    public int getMaxExtrusionWidth() {
        return mMaxExtrusionWidth;
    }

    // 注意清理 防止内存泄露
    private void clearBreathingAnimator() {
        if (mBreathingAnimator != null && mBreathingAnimator.isRunning()) {
            mBreathingAnimator.cancel();
            mBreathingAnimator = null;
        }
    }

    @Override
    public void onComponentBoundToWindow(Component component) {
    }

    @Override
    public void onComponentUnboundFromWindow(Component component) {
        clearBreathingAnimator();
    }


    public interface OnRandomDragListener {
        // 开始拖拽
        void onStartDrag();

        // 停止拖拽
        void onStopDrag();
    }

    public void setOnRandomDragListener(OnRandomDragListener listener) {
        this.mDragListener = listener;
    }
}
